package com.xiyi.shouxin.controller.websocket;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.google.gson.Gson;
import com.xiyi.shouxin.controller.pojo.PracticeData;
import com.xiyi.shouxin.dao.user.PiciRecordRepository;
import com.xiyi.shouxin.dao.user.UserRepository;
import com.xiyi.shouxin.entity.user.Cpr;
import com.xiyi.shouxin.entity.user.PiciRecord;
import com.xiyi.shouxin.entity.user.Practice;
import com.xiyi.shouxin.entity.user.User;
import com.xiyi.shouxin.entity.user.mapper.UserMapper;
import com.xiyi.shouxin.global.PracticeDataType;
import com.xiyi.shouxin.service.PracticeService;

/**
 * WebSocket 处理器 - 心肺复苏练习实时数据处理
 * 
 * 主要功能：
 * 1. 处理用户端发送的练习数据
 * 2. 管理员实时监控用户练习过程
 * 3. 数据转发和实时通信
 * 4. 练习质量评估和记录
 * 
 * @author system
 */
@Component
public class EchoHandler extends TextWebSocketHandler {
    
    /** JSON 解析工具 */
    private Gson gson = new Gson();
    
    /** 用户ID -> 练习ID 映射表，用于跟踪用户当前练习状态 */
    private final Map<Long, Long> uidPidMap = new ConcurrentHashMap<>();
    
    /** 管理员ID -> WebSocket会话 映射表，用于管理员实时监控 */
    private final Map<Long, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
    
    @Autowired
    private PracticeService practiceService;
    
    @Autowired
    private PiciRecordRepository piciRecordRepository;
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private Logger logger;

    /**
     * 处理 WebSocket 文本消息
     * 
     * @param session WebSocket 会话
     * @param message 接收到的文本消息
     */
    @Override
    public void handleTextMessage(@NonNull WebSocketSession session, @NonNull TextMessage message) {
        String msg = message.getPayload();

        // 解析接收到的 JSON 数据为 PracticeData 对象
        PracticeData data = gson.fromJson(msg, PracticeData.class);

        // 验证消息类型是否有效
        if (data.getType() == null) {
            return;
        }
        
        Long piciId = null;
        
        // 处理批次完成消息
        if (data.getType().intValue() == PracticeDataType.FINISH) {
            piciId = data.getPiciId();
            if (piciId != null) {
                // 创建批次记录并标记为完成
                PiciRecord pici = new PiciRecord();
                pici.setIsOver(1);
                try {
                    piciRecordRepository.update(piciId, pici);
                } catch (Exception e) {
                    logger.error("{}批次完成失败", piciId, e);
                }
            }
            return;
        }
        
        // 处理管理员监控消息
        if (data.getType().intValue() == PracticeDataType.JIANKONG) {
            // 验证管理员ID
            if (data.getAdminId() == null || data.getAdminId() == 0) {
                return;
            }

            // 保存管理员 WebSocket 会话
            sessionMap.put(data.getAdminId(), session);
            
            // 创建新的练习批次
            PiciRecord pici = new PiciRecord();
            pici.setAdminId(data.getAdminId());
            pici.setCreatedAt(new java.sql.Timestamp(new Date().getTime()));
            pici.setIsOver(0);
            
            try {
                // 结束管理员之前的批次
                piciRecordRepository.finishByAdminId(data.getAdminId());
                // 创建新批次
                piciId = piciRecordRepository.create(pici);
                
                // 返回批次信息给管理员
                PracticeData resp = new PracticeData();
                resp.setType(data.getType());
                resp.setAdminId(data.getAdminId());
                resp.setPiciId(piciId);
                session.sendMessage(new TextMessage(gson.toJson(resp)));
            } catch (Exception e) {
                logger.error("admin{}创建批次失败", data.getAdminId(), e);
            }
            logger.info("{}监控成员训练", msg);
            return;
        }
        
        // 验证用户ID
        if (data.getUid() == null || data.getUid() == 0) {
            return;
        }
        
        // 验证练习数据
        if (!StringUtils.hasText(data.getData())) {
            return;
        }
        
        User user = null;

        try {
            // 根据用户ID查找用户信息
            user = userRepository.findById(data.getUid(), new UserMapper());
            
            // 如果用户有关联的管理员，转发数据给管理员
            if (user != null && user.getAdminId() != null) {
                WebSocketSession s = sessionMap.get(user.getAdminId());
                if (s != null) {
                    if (s.isOpen()) {
                        // 获取管理员当前的练习批次
                        PiciRecord pici = piciRecordRepository.findLastNotOverByAdminId(user.getAdminId());
                        if (pici != null) {
                            piciId = pici.getId();
                            // 转发用户练习数据给管理员
                            s.sendMessage(message);
                        }
                    } else {
                        // 会话已关闭，移除映射
                        sessionMap.remove(user.getAdminId());
                    }
                }
            }
        } catch (Exception e) {
            logger.error("发送练习数据异常", e);
        }
        
        // 处理前端更新动画消息（不需要特殊处理）
        if (data.getType().intValue() == PracticeDataType.UPDATE) {
            return;
        }
        
        // 处理回弹不足消息
        if (data.getType().intValue() == PracticeDataType.HUITANBUZU) {
            Long practiceId = uidPidMap.get(data.getUid());
            if (practiceId != null) {
                try {
                    // 记录回弹不足情况
                    practiceService.notrestPractice(practiceId);
                } catch (Exception e) {
                    logger.error("回弹不足异常", e);
                }
            }
        }
        
        // 处理开始非考核练习消息
        if (data.getType().intValue() == PracticeDataType.KAISHIFEIKAOHE) {
            if (data.getUid() != null && data.getUid() != 0) {
                try {
                    // 结束用户之前的练习
                    Long practiceId = uidPidMap.get(data.getUid());
                    if (practiceId != null) {
                        practiceService.endPractice(data.getUid(), practiceId);
                    }
                    
                    // 获取管理员ID
                    Long adminId = null;
                    if (user != null) {
                        adminId = user.getAdminId();
                    }
                    
                    // 开始新的非考核练习
                    Practice practice = practiceService.startPractice(data.getUid(), adminId, piciId);
                    uidPidMap.put(data.getUid(), practice.getId());
                    data.setId(practice.getId());
                    session.sendMessage(new TextMessage(gson.toJson(data)));
                } catch (Exception e) {
                    logger.error("开始练习异常", e);
                }
            }
        }
        
        // 处理开始考核练习消息
        if (data.getType().intValue() == PracticeDataType.KAISHIKAOHE) {
            if (data.getUid() != null && data.getUid() != 0) {
                try {
                    // 结束用户之前的练习
                    Long practiceId = uidPidMap.get(data.getUid());
                    if (practiceId != null) {
                        practiceService.endPractice(data.getUid(), practiceId);
                    }
                    
                    // 获取管理员ID
                    Long adminId = null;
                    if (user != null) {
                        adminId = user.getAdminId();
                    }
                    
                    // 开始新的考核练习
                    Practice practice = practiceService.startCheckPractice(data.getUid(), adminId, piciId);
                    uidPidMap.put(data.getUid(), practice.getId());
                    data.setId(practice.getId());
                    session.sendMessage(new TextMessage(gson.toJson(data)));
                } catch (Exception e) {
                    logger.error("开始练习异常", e);
                }
            }
        }
        
        // 处理练习进行中消息
        if (data.getType().intValue() == PracticeDataType.JINGXINGZHONG) {
            Long practiceId = uidPidMap.get(data.getUid());
            if (practiceId != null) {
                try {
                    // 解析16进制数据：时间(2-6位)和深度(8-12位)
                    Integer time = Integer.parseInt(data.getData().substring(2, 6), 16);
                    Integer depth = Integer.parseInt(data.getData().substring(8, 12), 16);
                    
                    // 创建CPR练习数据记录
                    Cpr cpr = new Cpr();
                    cpr.setUid(data.getUid());
                    
                    // 深度数据转换：从整数转换为小数（除以1000）
                    BigDecimal value = new BigDecimal(depth);
                    value = value.divide(new BigDecimal(1000));
                    BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP);
                    cpr.setDepth(roundedValue.doubleValue());
                    
                    // 计算练习质量
                    cpr.setQualified(practiceService.calQualified(cpr.getDepth(), time).getQualified());
                    cpr.setPracticeId(practiceId);
                    cpr.setTime(time);
                    cpr.setMillisecond(data.getDate());
                    cpr.setCreatedAt(data.getDate().toString());
                    
                    // 保存练习数据
                    practiceService.practiceData(cpr);
                } catch (Exception e) {
                    logger.error("保存练习数据{}异常", msg, e);
                }
            }
        }
        
        // 处理练习结束消息
        if (data.getType().intValue() == PracticeDataType.JIESHU) {
            Long practiceId = uidPidMap.get(data.getUid());
            if (practiceId != null) {
                try {
                    // 结束当前练习
                    practiceService.endPractice(data.getUid(), practiceId);
                } catch (Exception e) {
                    logger.error("结束练习异常", e);
                }
            }
        }
    }
}
